# Author: David Avsajanishvili
# Contact: avsd05@gmail.com

"""
Converts UseCaseMaker XML file to ASCIIDOC source
Copyright (c) David Avsajanishvili, 2009
"""


import ucm_xmls
from pyxmls import *
import getopt, os, re, codecs

TOP_COMMENT = \
r"""// ''''''''''''''''''''''''''''''''''''''''''''''''''
// THIS FILE IS GENERATED AUTOMATICALLY - DON'T EDIT!
// ''''''''''''''''''''''''''''''''''''''''''''''''''
// Use Cases retrieved from UseCaseMaker
// XML file with help of ucm2asciidoc script.
// ''''''''''''''''''''''''''''''''''''''''''''''''''

"""

TAB_HEADER = """
[cols="3m,12",options="header"]
|==========================================================
"""

TAB_FOOTER = """
|==========================================================
"""


def asciidoc_labeled(caps, vals):
    ret = ""
    for i in range(len(caps)):
        if vals[i]:
            ret += "%s:: \n%s\n" % (caps[i],vals[i])
    return "\n--\n" + ret + "--\n" if ret.strip() else ""

def uc_maketable(uc):
    """
    Makes AsciiDoc-formatted tables from Use Cases
    """

    ret = ""
    
    # Main flow
    ret += TAB_HEADER + "|%(Prefix)s%(ID)s  | Main success scenario" % uc.__dict__

    alts = [] #(alternatives list)
    for s in uc.steps:
        if s.stepType in ('Default', 'Child'):
            ret += "\n|%(Name)s |%(description)s" % s.__dict__
        if s.stepType == 'Alternative':
            alts.append(s)
        
    ret += TAB_FOOTER

    # Extensions
    for als in alts:
        ret += TAB_HEADER + "|Extension %(Name)s  | %(description)s" % als.__dict__

        for s in uc.steps:
            if s.ID == als.ID and s.Prefix == als.Prefix and s.stepType == 'AlternativeChild':
                ret += "\n|%(Name)s |%(description)s" % s.__dict__

        ret += TAB_FOOTER

    ret += "\n\n"
    return ret

def ucmodel_to_asciidoc(
        U,
        cpt_char = r'=',
        title_char = r'-',
        cpt_title = ''):

    """
    Renders UseCaseMaker model, deserialized from XML file, to ASCIIDOC.
    """
        
    ret = ""

    # Render Use Cases

    for uc in U.model.usecases:
        uc_nm = "%(Name)s (%(Prefix)s%(ID)s) " % uc.__dict__
        uc_ttl = title_char * len(uc_nm)
        dsc = uc.attributes.description
        uc_table = uc_maketable(uc)
        notes = "" if (not uc.attributes.notes) else (
"""
[NOTE]
============================
%s
============================
""" % (uc.attributes.notes,))

        labels = asciidoc_labeled(
            ['Pre-Conditions', 'Post-Conditions', 'Trigger (%s)' % uc.trigger.eventType],
            [uc.preconditions, uc.postconditions, uc.trigger.description])
        
        prose = uc.prose

        ret += """
%(uc_nm)s
%(uc_ttl)s

// Description:
%(dsc)s

// Labeled list:
%(labels)s

// Notes:
%(notes)s

// Step Flows:
%(uc_table)s

// Prose:
%(prose)s

// <<<< End of UseCase <<<<

""" % locals()

    #Adding Main Caption title
    if cpt_char and cpt_title:
        ret = """%s
%s


%s""" % (cpt_title, cpt_char * len(cpt_title), ret)

    return ret


def main(argv):
    """
    Converts UseCaseMaker file to Use Cases
    in differnet human-readable formats,
    using AsciiDoc.

    Usage:
        %(command)s [options] usecasemaker_filename
        
    Options:
        -c, --title-char=TITLECHAR
            Characters for titles. When only one character
            specified, it is used to underline titles of Use Cases.
            If more than one, the first is used to underline
            title of document, the second - to underline titles
            of the Use Cases.
            Default: "=-"
        -f, --format
            Output format. Format can be:
                * asciidoc -- AsciiDoc source
                * docbook -- DocBook XML, generated by asciidoc tool
                * html -- HTML, generated by asciidoc tool
                * chunked -- chunked HTML (a2x)
                * htmlhelp -- HtmlHelp files (a2x)
                * manpage -- MAN page (a2x)
                * pdf -- PDF file (a2x, dblatex)
                * text -- plain text file (a2x)
                * xhtml -- XHTML file (a2x)
                * dvi -- DVI file (a2x, dblatex)
                * ps -- PostScript file (a2x, dblatex)
                * tex -- TeX file (a2x, dblatex).
        -o, --output=FILENAME
            Output file. By default - usecasemaker_filename with
            appropriate extension
        -v, --verbose
            Verbosely print processing information
        -t, --title
            Title of AsciiDoc document. Used only in case when
            --title-char consists of two characters.
            Default: usecasemaker_filename without extension
            
    Notes:
        * To build a separate document default --title-char
          must be used. This option is useful when
          including Use Cases in another AsciiDoc file
          as a section.
        * When using --format other than asciidoc,
          the AsciiDoc must be installed (asciidoc and a2x
          executables must be available).

    License:
        Copyright (c) 2009, David Avsajanishvili
        The tool is released under modified BSD license

    See Also:
        * UseCaseMaker: http://use-case-maker.sourceforge.net
        * AsciiDoc:     http://www.methods.co.nz/asciidoc/index.html
    """

    command = os.path.split(argv[0])[1]
    params = {}
    cpt_char = None
    verbose = False
    format = 'asciidoc'

    #Extract options
    try:
        opts, args = getopt.getopt(
            argv[1:],
            "c:f:o:vt:",
            ["title-char=", "format=",
             "output=", "verbose", "title="])

        infile = unicode(args[0],"utf8")
        outfile = None
        title = outfile

    except getopt.GetoptError, err:
        print main.__doc__ % locals()
        print "Error: %s" % err
        return -2
    except IndexError, err:
        print main.__doc__ % locals()
        print "Error: File not specified."
        return -2        

    
    for o, a in opts:	
        if   o in ("-c", "--title-char"):
            a = unicode(a,"utf8").strip()
            if len(a) > 1:
                params['cpt_char'] = a[0]
                params['title_char'] = a[1]
            else:
                params['cpt_char'] = ''
                params['title_char'] = a
        elif o in ("-v", "--verbose"):
            verbose = True
        elif o in ("-o", "--output"):
            outfile = unicode(a,"utf8")
        elif o in ("-f", "--format"):
            format = unicode(a,"utf8")
        elif o in ("-t", "--title"):
            title = unicode(a,"utf8")
    params['cpt_title'] = title

    outfile = outfile or u"%s.%s" % (
        os.path.splitext(os.path.split(infile)[1])[0],
        {'asciidoc':'asciidoc',
         'docbook':'xml',
         'html':'html'}.get(format,'xml'))

    # Deserialize
    serializer = XmlSerializer()
    serializer.silent = not verbose
    U = serializer.deserialize(infile, ucm_xmls.UCMDocument)

    # Convert Model to ASCIIDOC
    ret = TOP_COMMENT
    ret = ret + ucmodel_to_asciidoc(U, **params)

    if format == 'asciidoc':
        # Write ASCIIDOC
        f = open(outfile, "w")
        f.write(codecs.encode(ret,"utf8"))
        f.close()
    else:
        # Generate ASCIIDOC
        try:
            (f1,f2) = os.popen4('asciidoc -b%s -o"%s" %s -' %
                        (
                            ('xhtml11' if format=='html' else 'docbook'),
                            outfile,
                            '--verbose' if verbose else '',
                        )
                )
            f1.write(codecs.encode(ret,"utf8"))
            f1.close()
            print f2.read()
        finally:
            if f1: f1.close()
            if f2: f2.close()

        if format in ['chunked','htmlhelp','manpage','pdf','text','xhtml','dvi','ps','tex']:
            os.system('a2x -f%s -s %s "%s"' %
                      (
                          format,
                          '--verbose' if verbose else '',
                          outfile
                      )
                )
    
